package com.beerandjesus.sportofkings.handicapper.dao;

import com.beerandjesus.sportofkings.handicapper.model.TurfSire;
import com.beerandjesus.sportofkings.handicapper.model.TurfSireImpl;
import com.beerandjesus.sportofkings.handicapper.dao.aspect.TransactionBoundary;

import java.sql.SQLException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Connection;
import java.io.*;
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.List;
import java.util.ArrayList;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.springframework.core.io.ClassPathResource;

/**
 * Date: Jun 7, 2012
 * Time: 6:29:37 PM
 */
public class TurfSireDAOImpl extends AbstractDAOImpl implements TurfSireDAO {

    private static final String LEADING_TURF_SIRES = "leading_turf_sires";
    private static final MathContext CTX = new MathContext(2);
    private static final BigDecimal FIFTEEN_PERCENT = new BigDecimal(.15d, CTX);
    private String[] baseDataFiles;

    @TransactionBoundary(datasources= Database.Datasource.TURF_SIRE)
    public void buildDatabase() throws DAOException {
        Connection connection = getConnectionManager().getTurfSireDatabaseConnection();
        if (getBaseDataFiles() == null || getBaseDataFiles().length == 0) {
            throw new DAOException("No base data files provided");
        }
        executeStatementIgnoringException(connection, "drop table " + LEADING_TURF_SIRES);
        executeStatement(connection, "create table " + LEADING_TURF_SIRES +
                " (name varchar(100), percentage decimal(3,2))");
        PreparedStatement insert;
        BufferedReader r;
        List<BaseSireData> sires = new ArrayList<BaseSireData>();
        try {
            for (String res : getBaseDataFiles()) {
                ClassPathResource cpr = new ClassPathResource(res);

                r = new BufferedReader(new InputStreamReader(cpr.getInputStream()));
                String line;
                try {
                    while ((line = r.readLine()) != null) {
                        if (line.trim().equals("")) {
                            continue;
                        }
                        String[] elements = line.split("\t+");
                        if (elements.length != 3) {
                            throw new DAOException("Unexpected format found in line: " + line);
                        }
                        String name = elements[0];
                        name = name.replaceAll("=", "");
                        name = name.replaceAll("\\([A-Z]+\\)", "");
                        final String theName = name.toUpperCase().trim();

                        String s = elements[1].trim();
                        String w = elements[2].trim();

                        BaseSireData existing = (BaseSireData) CollectionUtils.find(sires, new Predicate() {
                            public boolean evaluate(Object object) {
                                BaseSireData d = (BaseSireData) object;
                                return (d.name.equals(theName));
                            }
                        });
                        if (existing != null) {
                            int starts = new Integer(s) + existing.starts;
                            int wins = new Integer(w) + existing.wins;
                            existing.starts = starts;
                            existing.wins = wins;
                        } else {
                            sires.add(new BaseSireData(theName, new Integer(s), new Integer(w)));
                        }
                    }
                } finally {
                    if (r != null) {
                        r.close();
                    }
                }
            }
            for (BaseSireData d : sires) {
                if (d.starts < 5) {
                    continue;
                }
                BigDecimal percentage;
                percentage = new BigDecimal(d.wins)
                        .divide(new BigDecimal(d.starts), CTX);
                if (percentage.compareTo(FIFTEEN_PERCENT) < 0) {
                    continue;
                }
                insert = connection.prepareStatement("insert into " + LEADING_TURF_SIRES +
                        " (name, percentage) values (?, ?)");
                try {
                    insert.setString(1, d.name);
                    insert.setBigDecimal(2, percentage);
                    insert.execute();
                } finally {
                    insert.close();
                }
            }
        } catch (IOException e) {
            throw new DAOException("Error reading base data file", e);
        } catch (SQLException e) {
            throw new DAOException("Error inserting data", e);
        }


    }

    @TransactionBoundary(datasources= Database.Datasource.TURF_SIRE)
    public int getRowCount() throws DAOException {
        Connection connection = getConnectionManager().getTurfSireDatabaseConnection();
        return getRowCount(connection, LEADING_TURF_SIRES);
    }

    public TurfSire getTurfSireByName(String name) throws DAOException {
        Connection connection = getConnectionManager().getTurfSireDatabaseConnection();
        if (StringUtils.isEmpty(name)) {
            return null;
        }
        PreparedStatement smt = null;
        try {
            smt = connection.prepareStatement("select * from " + LEADING_TURF_SIRES + " where name = ?");
            smt.setString(1, name.toUpperCase());
            ResultSet rs = smt.executeQuery();
            try {
                if (rs == null || !rs.next()) {
                    return null;
                }
                String h = rs.getString("name");
                BigDecimal p = rs.getBigDecimal("percentage");
                TurfSireImpl ts = new TurfSireImpl();
                ts.setName(h);
                ts.setWinPercentage(p);
                return ts;
            } finally {
                if (rs != null) {
                    try {
                        rs.close();
                    } catch (SQLException e) {
                        // ignore
                    }
                }
            }
        } catch (SQLException e) {
            throw new DAOException("Error fetching sire by name " + name, e);
        } finally {
            if (smt != null) {
                try {
                    smt.close();
                } catch (SQLException e) {
                    // ignore
                }
            }
        }
    }

    public String[] getBaseDataFiles() {
        return baseDataFiles;
    }

    public void setBaseDataFiles(String[] baseDataFiles) {
        this.baseDataFiles = baseDataFiles;
    }

    private class BaseSireData {
        String name;
        int starts;
        int wins;


        public BaseSireData(String name, int starts, int wins) {
            this.name = name;
            this.starts = starts;
            this.wins = wins;
        }

        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            BaseSireData that = (BaseSireData) o;

            return !(name != null ? !name.equals(that.name) : that.name != null);

        }

        public int hashCode() {
            return (name != null ? name.hashCode() : 0);
        }
    }

}
